#include <mysql.h>

#include <iostream>
#include "rpc/server.h"

#include "opencv2/opencv.hpp"

float *registration_image(cv::Mat &image_input, int *face_count, int *code);

void print_error_message(MYSQL *connection){
    if (mysql_errno(connection)) {
        fprintf(stderr, "mysql error %d: %s\n", mysql_errno(connection), mysql_error(connection));
    }
}

int update_feature(MYSQL *connection, std::string &feature_str, int relation_id){
    char query_sql[256 * 1024] = {0};
    sprintf(query_sql, "update relation set feature = \'%s\' where id = %d", feature_str.c_str(), relation_id);
    //printf("%s\n", query_sql);
    int query_result = mysql_query(connection, query_sql);
    int update_num;
    if(query_result){
        print_error_message(connection);
        update_num = 0;
    } else {
        printf("Update %lu rows\n",(unsigned long)mysql_affected_rows(connection));
        update_num = (int)mysql_affected_rows(connection);
    }
    return update_num;
}

int registration_mysql(int relation_id, int picture_id){
    MYSQL *connection = mysql_init(NULL);
    if (connection == NULL) {
        printf("mysql_init failed!\n");
        return EXIT_FAILURE;
    }

    connection = mysql_real_connect(connection, "localhost", "lbtc", "sxfMd4_f12508ccsdfdf", "recognition", 0, NULL, 0);

    if (connection) {
        printf("Connection success! ");
    } else {
        print_error_message(connection);
        mysql_close(connection);
        return 1;
    }

    int face_count = 0;
    int code = 1000;
    float *face_feature = 0;
    std::string feature_str = "";
    char query_sql[256] = {0};
    sprintf(query_sql, "select * from picture where id = %d limit 1", picture_id);
    int query_result = mysql_query(connection, query_sql);
    if(query_result){
        print_error_message(connection);
        mysql_close(connection);
        return 2;
    } else {
        MYSQL_RES *res_ptr = mysql_store_result(connection);
        if(res_ptr) {
            printf("query %lu Rows ",(unsigned long)mysql_num_rows(res_ptr));
            int num_fields = mysql_num_fields(res_ptr);
            MYSQL_ROW row;
            while((row = mysql_fetch_row(res_ptr)))  {
                unsigned long *field_lengths = mysql_fetch_lengths(res_ptr);
                for(int i = 0; i < num_fields; i++){
                    if(i == 1){
                        std::vector<uchar> image_raw_data(field_lengths[i]);
                        for(unsigned int j = 0; j < field_lengths[i]; j++) {
                            image_raw_data[j] = ((uchar *)(row[i]))[j];
                        }
                        cv::Mat img = cv::imdecode(image_raw_data, CV_LOAD_IMAGE_COLOR);
                        //img = cv::imread("/home/ubuntu/cj.jpg");
                        //cv::imwrite("/home/ubuntu/faceee.jpg", img);
                        face_feature = registration_image(img, &face_count, &code);
                        if(code == 0){
                            for(int m = 0; m < 512; m++){
                                feature_str += (std::to_string(face_feature[m]) + ",");
                            }
                            free(face_feature);
                            printf("registration success\n");
                        } else if(img.cols > img.rows) {
                            int code_ClockWise90 = -1;
                            cv::Mat img_ClockWise90;
                            transpose(img, img_ClockWise90);
                            flip(img_ClockWise90, img_ClockWise90, 1);
                            //cv::imwrite("/home/ubuntu/faceee90.jpg", img_ClockWise90);
                            face_feature = registration_image(img_ClockWise90, &face_count, &code_ClockWise90);
                            if(code_ClockWise90 == 0){
                                for(int m = 0; m < 512; m++){
                                    feature_str += (std::to_string(face_feature[m]) + ",");
                                }
                                free(face_feature);
                                code = 0;
                                printf("ClockWise90 registration success\n");
                            } else {
                                int code_ClockWise270 = -1;
                                cv::Mat img_ClockWise270;
                                transpose(img, img_ClockWise270);
                                flip(img_ClockWise270, img_ClockWise270, 0);
                                //cv::imwrite("/home/ubuntu/faceee270.jpg", img_ClockWise270);
                                face_feature = registration_image(img_ClockWise270, &face_count, &code_ClockWise270);
                                if(code_ClockWise270 == 0){
                                    for(int m = 0; m < 512; m++){
                                        feature_str += (std::to_string(face_feature[m]) + ",");
                                    }
                                    free(face_feature);
                                    code = 0;
                                    printf("ClockWise270 registration success\n");
                                }
                            }
                        }
                    } else {
                    }
                }
            }
            if (mysql_errno(connection)) {
                fprintf(stderr, "Retrive error:%s\n", mysql_error(connection));
            }
            mysql_free_result(res_ptr);
        } else {
            print_error_message(connection);
            mysql_close(connection);
            return 3;
        }
    }
    if(code == 0){
        int update_num = update_feature(connection, feature_str, relation_id);
        if(update_num != 1 && update_num != 0){
            code = 1001;
        }
    }
    mysql_close(connection);
    printf("\n");
    return code;
}

int main(int argc, char *argv[]) {
    //registration_mysql(1006, 1001);
    rpc::server srv("127.0.0.1", 18080);

    // note: the signature is automatically captured
    srv.bind("registration_mysql", &registration_mysql);
    srv.run();
    return 0;
}
